/*
 * PhraseDictionary_gtest.cpp
 *
 *  Created on: Nov 24, 2012
 *      Author: b
 */

#include <gtest/gtest.h>
#include <memory>
#include <vector>
#include "../physical_layer/file_system/Phrase.h"
#include "../physical_layer/file_system/PhraseDictionary.h"

using std::vector;
using physical::Phrase;
using physical::PhraseDictionary;
typedef physical::PhraseDictionary::Record Record;

/**
 * Test Suite de la clase PhraseDictionary
 */
class PhraseDictionaryTestFixture : public ::testing::Test
{

public:

	std::string m_fileName;

	PhraseDictionaryTestFixture()
    {
        const ::testing::TestInfo* const test_info =
                ::testing::UnitTest::GetInstance()->current_test_info();

        std::string filename(test_info->name());
        filename.append(".");
        filename.append(test_info->test_case_name());
        filename.append(".tmp");

        this->m_fileName = filename;
    }

    virtual ~PhraseDictionaryTestFixture()
    {
    }

    void SetUp()
    {
    }

    void TearDown()
    {
    }

    const char* getFileNameForTest() {
        return m_fileName.c_str();
    }

};

/**
 * Test Add and retrieve one phrase in the dictionary
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  AddAndRetrievePhrase)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest(),
	        std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	Phrase phrase ("frase 1", "miapellido", "minombre");

	size_t phraseRecordId = dictionary.add(phrase);

	Record phraseRecord(phraseRecordId, phrase);

	Record retrievedPhraseRecord = dictionary.get(phraseRecord.getPosition());

	ASSERT_TRUE(retrievedPhraseRecord == phraseRecord);

	ASSERT_TRUE(retrievedPhraseRecord.get() == phrase);

}

/**
 * Test
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  AddSeveralPhrasesAndRetrieveRandomly)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest()
	        , std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	vector <Phrase> phrases;
	vector <size_t> phraseRecordIds;
	vector <Record> phraseRecords;
	vector <Record> retrievedPhraseRecord;

	phrases.push_back(Phrase ("frase 1", "miapellido1", "minombre1"));

	phrases.push_back(Phrase ("frase 2", "miapellido2", "minombre2"));

	phrases.push_back(Phrase ("frase 3", "miapellido3", "minombre3"));

	for (vector <Phrase>::iterator it = phrases.begin(); it != phrases.end() ; ++it) {

		phraseRecordIds.push_back(dictionary.add(*it));

		phraseRecords.push_back(Record (phraseRecordIds.back(), *it));

	}

	ASSERT_TRUE(dictionary.get(phraseRecordIds[2]) == phraseRecords[2]);

	ASSERT_TRUE(dictionary.get(phraseRecordIds[1]).get() == phrases[1]);

}

/**
 * Test
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  GetFirstWithEmptyDictionary)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest(),
	        std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	ASSERT_THROW(dictionary.getFirst(), physical::DictionaryIsEmptyException);

}

/**
 * Test
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  AddSeveralPhrasesAndRetrieveSequentially)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest(),
	        std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	vector <Phrase> phrases;
	vector <size_t> phraseRecordIds;
	vector <Record> phraseRecords;
	vector <Record> retrievedPhraseRecord;

	phrases.push_back(Phrase ("frase 1", "miapellido1", "minombre1"));

	phrases.push_back(Phrase ("frase 2", "miapellido2", "minombre2"));

	phrases.push_back(Phrase ("frase 3", "miapellido3", "minombre3"));

	for ( auto it = phrases.begin(); it != phrases.end() ; ++it )
	{
		phraseRecordIds.push_back(dictionary.add(*it));

		phraseRecords.push_back(Record (phraseRecordIds.back(), *it));
	}

	for ( Record record = dictionary.getFirst() ;  ; record = dictionary.getNext(record) )
	{
		retrievedPhraseRecord.push_back(record);

		if( !dictionary.hasNext(record) )
		    break;
	}

	ASSERT_EQ( (unsigned int)3, retrievedPhraseRecord.size() );

	for (size_t i = 0; i < retrievedPhraseRecord.size(); ++i)
	{

		ASSERT_TRUE(retrievedPhraseRecord[i] == phraseRecords[i]);

		ASSERT_TRUE(retrievedPhraseRecord[i].get() == phrases[i]);

	}

}

/**
 * Test
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  AddPhrasesAndRetrieveSeqReopening)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest(),
	        std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	vector <Phrase> phrases;
	vector <size_t> phraseRecordIds;
	vector <Record> phraseRecords;
	vector <Record> retrievedPhraseRecord;

	phrases.push_back(Phrase ("frase 1", "miapellido1", "minombre1"));

	phrases.push_back(Phrase ("frase 2", "miapellido2", "minombre2"));

	phrases.push_back(Phrase ("frase 3", "miapellido3", "minombre3"));

	for (vector <Phrase>::iterator it = phrases.begin(); it != phrases.end() ; ++it)
	{
		phraseRecordIds.push_back(dictionary.add(*it));

		phraseRecords.push_back(Record (phraseRecordIds.back(), *it));
	}

	dictionary.close();

	dictionary.open( getFileNameForTest(), std::ios_base::in | std::ios_base::out );

	for (Record record = dictionary.getFirst() ;  ; record = dictionary.getNext(record))
	{
		retrievedPhraseRecord.push_back(record);

		if(!dictionary.hasNext(record)) break;
	}

	ASSERT_EQ( (unsigned int)3, retrievedPhraseRecord.size() );

	for (size_t i = 0; i < retrievedPhraseRecord.size(); ++i)
	{
		ASSERT_TRUE(retrievedPhraseRecord[i] == phraseRecords[i]);

		ASSERT_TRUE(retrievedPhraseRecord[i].get() == phrases[i]);
	}

}

/**
 * Test Add and retrieve one very long phrase in the dictionary
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  AddLongPhrase)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest(),
	        std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	Phrase phrase ( "fraselaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
			aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
			aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaargaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
			aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
			, "miapellido", "minombre");

	ASSERT_ANY_THROW(dictionary.add(phrase));
}

/**
 * Test
 *
 *
 */
TEST_F( PhraseDictionaryTestFixture,  AddMoreThanMaxPhrases)
{
	PhraseDictionary dictionary;

	dictionary.open( getFileNameForTest(),
	        std::ios_base::in | std::ios_base::out | std::ios_base::trunc );

	ASSERT_ANY_THROW(
		for( int i = 0; i < 2500; ++i )
		{
			dictionary.add(Phrase ("frase 1", "miapellido1", "minombre1"));
		}
	);

}


